package org.znxs.znagent_s.app;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.api.Advisor;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Component;
import org.znxs.znagent_s.advisors.MyLoggerAdvisor;
import org.znxs.znagent_s.chatMemory.FileBasedChatMemory;
import org.znxs.znagent_s.rag.QueryRewriter;

import java.util.List;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;


@Component
@Slf4j
/**
 * 恋爱智能体
 */
public class LoveApp {


    private final ChatClient chatClient;

    private final String fileDir = System.getProperty("user.dir") + "/chat-memory";

    private static final String SYSTEM_PROMPT = "扮演深耕恋爱领域的专家。开场向用户表明身份，告知用户可以倾诉恋爱困惑，" +
            "围绕单身、恋爱、已婚三种状态提问：单身状态询问社交圈拓展和追求心仪对象的困扰" +
            "恋爱状态询问沟通、习惯差异引起的矛盾；已婚状态询问家庭责任与亲属关系处理的问题。" +
            "引导用户详述问题经过、对方反应及自身想法，以便给出专属的解决方案。";

//    @Resource
//    private VectorStore loveAppVectorStore;

    public record LoveReport(String title, List<String> suggestions) {

    }

    // 初始化aiClient
    public LoveApp(ChatClient.Builder builder) {
        // 初始化基于内存的对话记忆 (Spring AI 自带的)
//        ChatMemory chatMemory = new InMemoryChatMemory();
        // 基于文件存储对话记忆 (自定义)
        FileBasedChatMemory chatMemory = new FileBasedChatMemory(fileDir);
        this.chatClient = builder
                .defaultSystem(SYSTEM_PROMPT)
                // 全局advisor 顾问
                .defaultAdvisors(
                        // 记忆顾问
                        new MessageChatMemoryAdvisor(chatMemory),
                        // 添加自定义重读Advisor 按需开启
//                        new ReReadAdvisor(),
                        // 添加自定义日志响应，按需开启
                        new MyLoggerAdvisor()

                )
                .build();
    }

    // 调用对话
    public String doChat(String text, String chatId) {
        // 调用 chatClient
        ChatResponse chatResponse = chatClient.prompt()
                .user(text)
                //   ✔️完成 需要了解这个参数的作用 为什么要设置chatId
                //  为什么它自己就能分辨第一个为记忆的key 第二个就为记忆数
                //  解答：懂了，看来官方文档，这个CHAT_MEMORY_CONVERSATION_ID_KEY 以及 CHAT_MEMORY_RETRIEVE_SIZE_KEY
                //  就是官方指定的advisor的用法，不需要我们自己去编写 阿里官方文档 ⬇️
                //  {@link https://java2ai.com/docs/1.0.0-M6.1/tutorials/memory/?spm=5176.29160081.0.0.2856aa5cB3s4ea}
                .advisors(advisorSpec -> advisorSpec
                        .param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .call()
                .chatResponse();
        String content = chatResponse.getResult().getOutput().getText();
//        log.info("content:\n{}", content);
        return content;
    }

    public LoveReport handleChatWithReport(String message, String chatId) {
        LoveReport loveReport = chatClient.prompt()
                .system(SYSTEM_PROMPT)
                .user(message)
                // 使用记忆advisor
                .advisors(advisorSpec -> advisorSpec
                        .param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 50))
                .call()
                .entity(LoveReport.class);
        log.info("Love report 结果: {}", loveReport);
        return loveReport;
    }

    @Resource
    private Advisor loveAppRagCloudAdvisor;

//    @Resource
//    private VectorStore pgVectorVectorStore;

    @Resource
    private QueryRewriter queryRewriter;

    public String doChatWithRag(String message, String chatId) {
        // 使用查询重写增强器  但是需要注意，查询重写有时候会失去本意，需要根据实际情况使用
//        message = queryRewriter.doQueryRewrite(message);
        log.info("用户输入：【{}】", message);

        ChatResponse chatResponse = chatClient
                .prompt()
                .user(message)
                // 使用记忆advisor
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)
                )
                // 采用 RAG 检索增强服务 (基于自定义向量存储 loveAppVectorStore)
//                .advisors(new QuestionAnswerAdvisor(loveAppVectorStore))
                // 采用 RAG 检索增强服务 (基于通义百炼自己的云知识库 advisor)
                .advisors(loveAppRagCloudAdvisor)
                // 采用 RAG 检索增强服务 (基于 PGVector 向量存储)
//                .advisors(new QuestionAnswerAdvisor(pgVectorVectorStore))
                // 采用 RAG 检索增强服务 (基于自定义的检索增强顾问 可以通过预设向量存储 和 元信息来配置检索过滤)
//                .advisors(LoveAppRagCustomAdvisorFactory.createRagCustomAdvisor(loveAppVectorStore, "恋爱"))

                .call()
                .chatResponse();
        String content = chatResponse.getResult().getOutput().getText();
        return content;
    }


    @Resource
    private ToolCallback[] allTools;

    /**
     * Function calling 工具调用方法
     *
     * @param message
     * @param chatId
     * @return
     */
    public String toolsCallTest(String message, String chatId) {
        log.info("用户输入：【{}】", message);

        String content = chatClient.prompt()
                .user(message)
                // 使用记忆advisor
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)
                )
                // 使用工具 这里导入的是自定义的工具集
                .tools(allTools)
                // 使用 ToolContext 自定义设置Tool方法传参
//                .tools(new SendEmailTool())
//                .toolContext(Map.of("user", "1556855894@qq.com"))
                .call()
                .content();
        return content;
    }



    @Resource
    private ToolCallbackProvider toolCallbackProvider;  // 官方提供的工具回调提供对象

    /**
     * Mcp 调用方法
     *
     * @param message
     * @param chatId
     * @return
     */
    public String toolsMcpTest(String message, String chatId) {
        log.info("用户输入：【{}】", message);

        String content = chatClient.prompt()
                .user(message)
                // 使用记忆advisor
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)
                )
                // 使用工具 这里导入的是 Spring ai 提供的 自动方法提供器
                .tools(toolCallbackProvider)
                .call()
                .content();
        return content;
    }


}
